<?php
/**
 * Oauth2 protocol
 * 
 * @author xiaogua <huangjunjing@bianhong.com>
 * @package Account
 * @version 0.0.1
 * @copyright bianhong.com 2011
 */

namespace Account\Action\Oauth\V2\Token;

use Account\Action\Misc;

class Index{
    
    /*
     * http://tools.ietf.org/html/draft-ietf-oauth-v2-18#section-5.2
     */
    const ERROR_INVALID_REQUEST        = "invalid_request";
    const ERROR_INVALID_CLIENT         = "invalid_client";
    const ERROR_UNAUTHORIZED_CLIENT    = "unauthorized_client";
    const ERROR_UNSUPPORTED_GRANT_TYPE = 'unsupported_grant_type';
    const ERROR_INVALID_GRANT          = 'invalid_grant';
    const ERROT_EXPIRED_TOKEN          = 'expired_token';
    const ERROR_INVALID_USER           = 'invalid_user';//grant为password时用户名或者密码错误
    
    const ERROR_SERVER_ERROR           ="server_error";
    
    const CODE_EXPIRES          = 3600; //code过期时间
    const ACCESS_TOKEN_EXPIRES  = 86400;    
    const REFRESH_TOKEN_EXPIRES = 2592000; 
    
    const ACCESS_TOKEN_LENGTH  = 16;
    const REFRESH_TOKEN_LENGTH = 16;

    function __construct() {
        if(!\F3::get('CACHE')){
            $this->_htal(self::ERROR_SERVER_ERROR);
            return;
        }
    }

    /*
     * search "grant_type" from http://tools.ietf.org/html/draft-ietf-oauth-v2-18
     */
    protected $_supported_grant_type = array(
        'refresh_token',
        'authorization_code',
        'password',
        'client_credentials',
        'bind'
    );
    protected $_defined_params = array(
        'grant_type'=>'required',
        'code'=>'required',
        'client_id'=>'required',
        'redirect_uri'=>'required',
        'password'=>'optional',
        'username'=>'optional',
        'refresh_token'=>'optional',
        'bind'=>'optional',
    );

//    protected $_password_params = array(
//        'grant_type'=>'required',
//        'client_id'=>'required',
//        'password'=>'required',
//        'username'=>'required',
//    );
//    
//   protected $_refresh_token_params = array(
//        'grant_type'=>'required',
//        'client_id'=>'required',
//    ); 
//   protected $_authorization_code_params = array(
//        'grant_type'=>'required',
//        'code'=>'required',
//        'client_id'=>'required',
//        'redirect_uri'=>'required',
//    );
    protected $_params = array();
    
    /*
     * 不同的授权类型处理方法不一样grant_type
     */
    public function post() {
        if(!$this->_validRequest()) {
            return;
        }
        
        
        switch ($this->_params['grant_type']){
            case 'password':
                $data=$this->getByPassword();
                break;
            case 'authorization_code';
                $data=$this->getByCode();
                break;
            case 'refresh_token';
                $data=$this->getByRefresh();
                break;
            case 'bind';
                $data=$this->getByBind();
                break;
//            case 'client_credentials';
//                $data=$this->getByCredentials();
//                break;
//            default:
//                echo 'test';
        }
        //如果数据都有，则刷新refresh_token
        
        if(empty($data['user_id'])   || ($data['user_id'] == 0)){
             $this->_htal(self::ERROR_INVALID_USER);
             return false;
        }
        
        $now = time();
        $accessToken   = 'token_'.Misc::generateCode(self::ACCESS_TOKEN_LENGTH).'.'.self::ACCESS_TOKEN_EXPIRES.'.'.$now.'.'.$data['user_id'];
        $refreshToken  = Misc::generateCode(self::REFRESH_TOKEN_LENGTH).'.'.self::REFRESH_TOKEN_EXPIRES.'.'.$now.'.'.$data['user_id'];
        $refresh = new \Axon('refresh_token');
        $refresh->refresh_token=$refreshToken;
        $refresh->user_id=$data['user_id'];
        $refresh->client_id=$this->_params['client_id'];
        $refresh->client_secret=$data['client_secret'];
        $refresh->expires_in=self::REFRESH_TOKEN_EXPIRES;
        $refresh->scope=$this->_params['scope'];
        $refresh->expires= $now+self::REFRESH_TOKEN_EXPIRES;
        $refresh->save();
        $response = array(
            'access_token'  => $accessToken,
            'expires_in'    => self::ACCESS_TOKEN_EXPIRES,
            'refresh_token' => $refreshToken,
            );
        $value = array(
            'access_token'  => $accessToken,
            'expires_in'    => self::ACCESS_TOKEN_EXPIRES,
            'refresh_token' => $refreshToken,
            'user_id'       => $data['user_id'],
            'client_id'     => $this->_params['client_id'],
            'client_secret' => $data['client_secret'],
            'client_name'   => $data['client_name'],
            'client_email'  => $data['client_email'],
            'user_name'     => $data['user_name'],
            'is_batch'     => $data['is_batch']
            );
          if($this->_params['grant_type'] == 'bind'){
            $value['bind'] = $data['bind'];
          }
        \Cache::set($accessToken, $value);
        header('Cache-Control: no-cache, must-revalidate');
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
        echo json_encode($response);
    }
    
    protected function _validParams($params) {
        $params = array_intersect_key($params, $this->_defined_params);
        $this->_params = $params;
        return true;
    }
    
    private function getByPassword(){
        $user=new \Axon('user');
        $user->load(array('email=:email', array(':email' => $this->_params['username'])));
        if($user->dry()){
                $this->_htal(self::ERROR_INVALID_USER);
                return false;
        }
        $userLogin=$user->load('email="' . $this->_params['username'] . '" AND password="'.md5($this->_params['password'].$user->password_extension).'"'); 
        if($userLogin->dry()){
                $this->_htal(self::ERROR_INVALID_USER);
                return false;
        }
        $client = new \Axon('client');
        $client->load('auth_client_id="' . $this->_params['client_id'] . '"');
        $user_dev=new \Axon('user_dev');
        $user_dev->load('user_id="' . $user->id . '');
        $data = array();
        $data['user_id']=$user->id;
        $data['client_secret']=$client->auth_client_secret;
        $data['client_name']=$client->name;
        $data['client_email']=$user_dev->dev_email;
        $data['user_name']=$user->email;        
        return $data;
    }
   private function getByBind(){
        $bind=new \Axon('user_profile_bind');
        $bind->load(array('bind=:bind', array(':bind' => $this->_params['bind'])));
        if($bind->dry()){
            $this->_htal(self::ERROR_UNAUTHORIZED_CLIENT);
            return false;
        }
        $user=new \Axon('user');
        $user->load('id="' .$bind->user_id. '"'); 
        
        $client = new \Axon('client');
        $client->load('auth_client_id="' . $this->_params['client_id'] . '"');
        $user_dev=new \Axon('user_dev');
        $user_dev->load('user_id="' . $user->id . '');
        $data = array();
        $data['user_id']=$user->id;
        $data['client_secret']=$client->auth_client_secret;
        $data['client_name']=$client->name;
        $data['client_email']=$user_dev->dev_email;
        $data['user_name']=$user->email;   
        $data['bind']=$bind->id;
        return $data;
    }
    private function getByCode(){
        $data = \Cache::get($this->_params['code']);
        \Cache::clear($this->_params['code']);
        return $data;
    }
    
    /*
     * 读取已经存在刷新令牌，组织数据后删除该记录
     */
    private function getByRefresh(){
         //判断刷新码是否过期
        $refreshToken = explode('.', $this->_params['refresh_token']);
        if ((time()-$refreshToken[2]) > self::REFRESH_TOKEN_EXPIRES ) {
            $this->_htal(self::ERROT_EXPIRED_TOKEN);
            return false;
        }
            
        $refresh_token=new \Axon('refresh_token');
	$refresh_token->load('refresh_token="'.  $this->_params['refresh_token'] .'"');
        if ($refresh_token->dry()) {
            $this->_htal(self::ERROR_INVALID_USER);
            return false;
        }
        if(empty($refresh_token->user_id)){
            $this->_htal(self::ERROR_INVALID_USER);
            return false;
        }
        $user_id = $refresh_token->user_id;
        
        $client = new \Axon('client');
        $client->load('auth_client_id="' . $this->_params['client_id'] . '"');

        
        $user_dev=new \Axon('user_dev');
        $user_dev->load('user_id="' . $user_id . '"');
        
        $user=new \Axon('user');
        $user->load('id="' . $user_id . '"');
        if ($user->dry()) {
            $this->_htal(self::ERROR_INVALID_USER);
            return false;
        }
        $data = array();
        $data['user_id']=$user_id;
        $data['client_secret']=$refresh_token->client_secret;
        $data['client_name']=$client->name;
        $data['client_email']=$user_dev->dev_email;
        $data['user_name']=$user->email;
        
        return $data;
    }
    protected function _validRequest() {
        
        if(!$this->_validParams($_POST)) {
            $this->_htal(self::ERROR_INVALID_REQUEST);
            return false;
        }
        
        if(!in_array($this->_params['grant_type'],$this->_supported_grant_type)) {
            $this->_htal(self::ERROR_UNSUPPORTED_GRANT_TYPE);
            return false;
        }
        
        $client_code=new \Axon('client_code');
	$client_code->load('client_id="'.  $this->_params['client_id'] .'"');
	if ($client_code->dry()) {
            $this->_htal(self::ERROR_UNAUTHORIZED_CLIENT);
            return false;
        }

        return true;
    }
    
    
    protected function _htal($error) {
        header('Cache-Control: no-cache, must-revalidate');
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
        echo json_encode(array('error' => $error));
    }

}
